package xin.marcher.wind.process.annoations;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import xin.marcher.wind.process.config.ProcessParser;
import xin.marcher.wind.process.enums.XmlReadFromEnum;
import xin.marcher.wind.process.factory.ProcessParserFactory;
import xin.marcher.wind.process.model.ProcessContextFactory;
import xin.marcher.wind.process.model.ProcessModel;

import java.util.ArrayList;
import java.util.List;

/**
 * @author marcher
 */
@Slf4j
public class ProcessNodeRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        try {
            /*
                AnnotationMetadata，这个是描述当前的注解的元数据
                @EnableProcessEngine 注解，通过注解名称，就可以通过 getAnnotationAttributes 拿到这个注解的属性集合
                拿到这个注解的属性集合之后，就可以拿到注解 value 的值，注解里定义的核心值, 就是流程定义文件名称
             */
            String configFile = (String) annotationMetadata.getAnnotationAttributes(EnableProcessEngine.class.getName()).get("value");
            XmlReadFromEnum readFrom = (XmlReadFromEnum) annotationMetadata.getAnnotationAttributes(EnableProcessEngine.class.getName()).get("readFrom");

            /*
                1. 解析得到流程
                通过 ClassPathXmlProcessParser，基于 classpath 类路径的 xml 处理解析组件，对 xml 配置文件进行解析, 就可以拿到一堆的 ProcessModel.
                ProcessModel: 每个 ProcessModel 其实代表了一个流程定义的配置数据，一个流程定义，就对应了一个 ProcessModel
                解析流程定义的文件，拿到所有流程定义对应的 ProcessModel 配置数据
             */
            ProcessParser processParser = new ProcessParserFactory(environment).create(configFile, readFrom);
            List<ProcessModel> processLists = processParser.parse();

            /*
                2. 注册 ProcessContextFactory
                BeanDefinitionBuilder，是 spring 提供的接口，构造一个 bean，基于 ProcessContextFactory 自定义类，来定义 bean
                bean 实例化的时候，构造函数的参数，解析出来的 process 定义数据
                基于 xml 解析出来的流程定义数据模型，会去封装成 ProcessContextFactory，是我们框架提供出来的最核心的 API
                这个持有了我们所有定义的流程数据，可以基于他去驱动各种流程的推进和执行，自动去执行补偿
             */
            BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(ProcessContextFactory.class);
            bdb.addConstructorArgValue(new ArrayList<>(processLists));
            // 依赖和引用 spring 容器里的其他 bean，springBeanInstanceCreator
            bdb.addConstructorArgReference("springBeanInstanceCreator");
            bdb.addConstructorArgReference("processStateStore");
            // 基于 spring 的 bean 定义注册中心，把自己构造的一个 bean 定义给注册进去就可以了
            beanDefinitionRegistry.registerBeanDefinition(ProcessContextFactory.class.getName(), bdb.getBeanDefinition());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
